package wid;

import robocode.AdvancedRobot;
import robocode.HitRobotEvent;
import robocode.ScannedRobotEvent;
import java.awt.Color;

/**
 * Implements the Pacifist Robocode robot, a lover, not a fighter.  Pacifist does not fight.  
 * It defends itself through evasion only. 
 * 
 * @author David Wilkie
 */
public class Pacifist extends AdvancedRobot {  

  double centerX = 0, centerY = 0;
  // For guessing whether an enemy has fired
  double enemyEnergy = 100;
  // For reversal of direction upon guess that enemy has fired
  int movementDirection = 1;
  // For keeping the gun pointed away from the enemy
  int gunDirection = -1;
  // When near a wall, robot moves back to center to avoid collision
  boolean nearWall = false;

  /** The main method of this (and every) Robocode robot. */
  public void run() {     
    centerX = getBattleFieldWidth() / 2;
    centerY = getBattleFieldHeight() / 2;
    setColors(Color.GREEN, Color.WHITE, Color.YELLOW);
    setTurnGunRight(100000);
  }
  
  /**
   * When another robot is detected, robot may need to perform evasion operations.
   * 
   * @param e ScannedRobotEvent the scanned robot's info
   */
  public void onScannedRobot(ScannedRobotEvent e) {
    // Turns Pacifist to face 30 degrees away from opponent
    // Adjust the heading if robot is expected to hit a wall
    setTurnRight(e.getBearing() + 90 + (30 * this.movementDirection));
    detectFire(e);
    // When robot is seen, sweep gun and radar to face opposite direction
    this.gunDirection *= -1;
    setTurnGunRight(100000 * gunDirection);
  }

  /**
   * Brings robot to center of the battlefield.
   */
  public void toCenter() {    
    boolean atCenter = false;
    if (!atCenter) {
      double toCenterX = centerX - getX();
      turnRight((toCenterX > 0 ? 90 : -90) - getHeading());
      ahead((int) Math.abs(toCenterX));
      double toCenterY = centerY - getY();
      turnRight((toCenterY > 0 ? 0 : 180) - getHeading());
      ahead((int) Math.abs(toCenterY));
    }
    nearWall = false;
  }
  
  /**
   * Helps maintain a correct count of the enemy robot's energy.
   * 
   * @param e HitRobotEvent the info of the robot that was hit
   */
  public void onRobotHit (HitRobotEvent e) {
    this.enemyEnergy = e.getEnergy();
  }
  
  /**
   * When the robot detects a small (<=3) energy drop in the scanned robot, it
   * changes its movement direction.  This code was adapted from "Secrets of
   * the Robocode Masters: Dodge Bullets" by Jae Marsh
   * 
   * @param e ScannedRobotEvent The scanned robot's info
   */
  public void detectFire(ScannedRobotEvent e) {
    // If the bot has small energy drop, assume it fired
    double energyChange = this.enemyEnergy - e.getEnergy();
    if (energyChange > 0 && energyChange <= 3) {
      this.movementDirection *= -1;
      avoidWall(e);
    }
    // Track the energy level
    this.enemyEnergy = e.getEnergy();
  }
  
  /**
   * Returns whichever is lesser: the distance to the nearest wall or ~25% of the 
   * distance to the scanned robot, divided by 4.  Because the Pacifist wants
   * to live, and because running into walls gets it closer to destruction, it 
   * makes itself less vulnerable to fire by avoiding wall collisions.
   * 
   * @param e ScannedRobotEvent the scanned robot
   */
  private void avoidWall(ScannedRobotEvent e) {
    double x = getX();
    double y = getY();
    if (x < 120 || y < 120 || getBattleFieldHeight() - y < 120 
        || getBattleFieldWidth() - x < 120) {
      nearWall = true;
    }
    // If going near a wall, go to the center instead
    if (nearWall) {    
      toCenter();
    }
    else {
      double dodgeDistance = Math.min(e.getDistance() / 4 + 25, 100);
      setAhead(dodgeDistance);
    }
  }  
}
